/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.IO;
using NDODS.DAP;
using NDODS.DAP.Exceptions;
using NDODS.DAP.Utils;

namespace NDODS.DAP.BaseTypes
{
    /// <summary> A <code>DSequence</code> in OPeNDAP can hold <em>N</em> sequentially accessed
    /// instances of a set of variables. In relation to the <code>DStructure</code>
    /// datatype, a <code>DSequence</code> is a table
    /// of N instances of a <code>DStructure</code>. Data in a
    /// <code>DSequence</code> is accessed row by row.
    /// <p/>
    /// Unlike its C++ counterpart, this class reads all of its rows on a
    /// <code>Deserialize</code>, which gives <code>DSequence</code> the same
    /// semantics as the other <code>BaseType</code> classes, eliminating the need
    /// to worry about <code>DSequence</code> as a special case.
    /// 
    /// </summary>
    /// <author>  jehamby
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="BaseType">
    /// </seealso>
    /// <seealso cref="DConstructor">
    /// </seealso>
    [Serializable]
    public class DSequence : DConstructor, IClientIO, ICloneable
    {
        /// <summary> Returns the OPeNDAP type name of the class instance as a <code>String</code>.
        /// 
        /// </summary>
        /// <returns> the OPeNDAP type name of the class instance as a <code>String</code>.
        /// </returns>
        public override String TypeName {
            get { return "Sequence"; }
        }

        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Returns the level of this sequence.
        /// 
        /// </summary>
        /// <returns> the level of this sequence.
        /// </returns>
        /// <summary> Sets the level of this sequence.
        /// 
        /// </summary>
        protected internal virtual int Level {
            get { return level; }

            set { this.level = value; }
        }

        /// <summary> Returns the number of rows in this <code>Sequence</code>.
        /// 
        /// </summary>
        /// <returns> the number of rows currently in this <code>Sequence</code>.
        /// </returns>
        public virtual int RowCount {
            get { return allValues.Count; }
        }

        /// <summary> Return an Enumeration that can be used to iterate over the members of
        /// a Sequence. This implementation provides access to the template
        /// elements of the Sequence, not the entire sequence. Each Object
        /// returned by the Enumeration can be cast to a BaseType.
        /// 
        /// </summary>
        /// <returns> An Enumeration
        /// </returns>
        public override IEnumerator Variables {
            get { return varTemplate.GetEnumerator(); }
        }

        /// <summary> The start of instance byte marker</summary>
        protected internal static sbyte START_OF_INSTANCE = (0x5A);

        /// <summary> The end of sequence byte marker</summary>
        protected internal static sbyte END_OF_SEQUENCE = (sbyte) SupportClass.Identity(0xA5);

        /// <summary> The variables in this <code>DSequence</code>, stored in a
        /// <code>Vector</code> of <code>BaseType</code> objects
        /// and used as a template for <code>Deserialize</code>.
        /// </summary>
        protected internal ArrayList varTemplate;

        /// <summary> The values in this <code>DSequence</code>, stored as a
        /// <code>Vector</code> of <code>Vector</code> of <code>BaseType</code>
        /// objects.
        /// </summary>
        protected internal ArrayList allValues;

        /// <summary> Level number in a multilevel sequence.</summary>
        private int level;

        /// <summary> Constructs a new <code>DSequence</code>.</summary>
        public DSequence() : this(null) {}

        /// <summary> Constructs a new <code>DSequence</code> with name <code>n</code>.
        /// 
        /// </summary>
        /// <param name="n">the name of the variable.
        /// </param>
        public DSequence(String n) : base(n) {
            varTemplate = ArrayList.Synchronized(new ArrayList(10));
            allValues = ArrayList.Synchronized(new ArrayList(10));
            level = 0;
        }

        /// <summary> Returns a clone of this <code>DSequence</code>.  A deep copy is performed
        /// on all data inside the variable.
        /// 
        /// </summary>
        /// <returns> a clone of this <code>DSequence</code>.
        /// </returns>
        public override Object Clone() {
            DSequence s = (DSequence) base.Clone();

            s.varTemplate = ArrayList.Synchronized(new ArrayList(10));

            for (int i = 0; i < varTemplate.Count; i++) {
                BaseType bt = (BaseType) varTemplate[i];
                s.varTemplate.Add(bt.Clone());
            }

            s.allValues = ArrayList.Synchronized(new ArrayList(10));

            for (int i = 0; i < allValues.Count; i++) {
                ArrayList rowVec = (ArrayList) allValues[i];
                ArrayList newVec = ArrayList.Synchronized(new ArrayList(10));
                for (int j = 0; j < rowVec.Count; j++) {
                    BaseType bt = (BaseType) rowVec[j];
                    newVec.Add(bt.Clone());
                }
                s.allValues.Add(newVec);
            }
            return s;
        }

        /// <summary> Returns the number of variables contained in this object. For simple and
        /// vector type variables, it always returns 1. To count the number
        /// of simple-type variable in the variable tree rooted at this variable, set
        /// <code>leaves</code> to <code>true</code>.
        /// 
        /// </summary>
        /// <param name="leaves">If true, count all the simple types in the `tree' of
        /// variables rooted at this variable.
        /// </param>
        /// <returns> the number of contained variables.
        /// </returns>
        public override int ElementCount(bool leaves) {
            if (!leaves)
                return varTemplate.Count;
            else {
                int count = 0;
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = varTemplate.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    BaseType bt = (BaseType) e.Current;
                    count += bt.ElementCount(leaves);
                }
                return count;
            }
        }

        /// <summary> Adds a variable to the container.
        /// 
        /// </summary>
        /// <param name="v">   the variable to add.
        /// </param>
        /// <param name="part">ignored for <code>DSequence</code>.
        /// </param>
        public override void addVariable(BaseType v, int part) {
            v.Parent = this;
            varTemplate.Add(v);
            if (v is DSequence)
                ((DSequence) v).Level = Level + 1;
        }

        /// <summary> Adds a row to the container.  This is assumed to contain a
        /// <code>Vector</code> of variables of the same type and in the same order
        /// as the variable template added with the <code>addVariable</code> method.
        /// 
        /// </summary>
        /// <param name="row">the <code>Vector</code> to add.
        /// </param>
        public void addRow(ArrayList row) {
            allValues.Add(row);
        }

        /// <summary> Gets a row from the container.  This returns a <code>Vector</code> of
        /// variables of the same type and in the same order as the variable template
        /// added with the <code>addVariable</code> method.
        /// 
        /// </summary>
        /// <param name="row">the row number to retrieve.
        /// </param>
        /// <returns> the <code>Vector</code> of <code>BaseType</code> variables.
        /// </returns>
        public ArrayList getRow(int row) {
            return (ArrayList) allValues[row];
        }

        /// <summary> Deletes a row from the container.
        /// 
        /// </summary>
        /// <param name="row">the row number to delete.
        /// </param>
        /// <throws>  ArrayIndexOutOfBoundsException if the index was invalid. </throws>
        public void delRow(int row) {
            allValues.RemoveAt(row);
        }

        /// <summary> Returns the named variable.  <b>Note:</b> In <code>DSequence</code>,
        /// this method returns the template variable, which holds no data.  If you
        /// need to get a variable containing data, use <code>getRow</code> or the
        /// <code>getVariable</code> method which takes a row number parameter.
        /// 
        /// </summary>
        /// <param name="name">the name of the variable.
        /// </param>
        /// <returns> the named variable.
        /// </returns>
        /// <throws>  NoSuchVariableException if the named variable does not </throws>
        /// <summary>                                 exist in this container.
        /// </summary>
        /// <seealso cref="DSequence.getVariable(int, String)">
        /// </seealso>
        public override BaseType getVariable(String name) {
            int dotIndex = name.IndexOf('.');

            if (dotIndex != - 1) {
                // name contains "."
                String aggregate = name.Substring(0, (dotIndex) - (0));
                String field = name.Substring(dotIndex + 1);

                BaseType aggRef = getVariable(aggregate);
                if (aggRef is DConstructor)
                    return ((DConstructor) aggRef).getVariable(field);
                    // recurse
                else {} // fall through to throw statement
            }
            else {
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = varTemplate.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    BaseType v = (BaseType) e.Current;
                    if (v.Name.Equals(name))
                        return v;
                }
            }
            throw new NoSuchVariableException("DSequence: getVariable()");
        }

        /// <summary> Gets the indexed variable. For a DSrquence this returns the <code>BaseType</code>
        /// from the <code>index</code>th column from the internal map <code>Vector</code>.
        /// 
        /// </summary>
        /// <param name="index">the index of the variable in the <code>Vector</code> Vars.
        /// </param>
        /// <returns> the indexed variable.
        /// </returns>
        /// <throws>  NoSuchVariableException if the named variable does not </throws>
        /// <summary>                                 exist in this container.
        /// </summary>
        public override BaseType getVar(int index) {
            if (index < varTemplate.Count)
                return ((BaseType) varTemplate[index]);
            else
                throw new NoSuchVariableException("DSequence.getVariable(" + index + " - 1)");
        }


        /// <summary> Returns the named variable in the given row of the sequence.
        /// 
        /// </summary>
        /// <param name="row"> the row number to retrieve.
        /// </param>
        /// <param name="name">the name of the variable.
        /// </param>
        /// <returns> the named variable.
        /// </returns>
        /// <throws>  NoSuchVariableException if the named variable does not </throws>
        /// <summary>                                 exist in this container.
        /// </summary>
        public virtual BaseType getVariable(int row, String name) {
            int dotIndex = name.IndexOf('.');

            if (dotIndex != - 1) {
                // name contains "."
                String aggregate = name.Substring(0, (dotIndex) - (0));
                String field = name.Substring(dotIndex + 1);

                BaseType aggRef = getVariable(aggregate);
                if (aggRef is DConstructor)
                    return ((DConstructor) aggRef).getVariable(field);
                    // recurse
                else {} // fall through to throw statement
            }
            else {
                ArrayList selectedRow = (ArrayList) allValues[row];
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = selectedRow.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    BaseType v = (BaseType) e.Current;
                    if (v.Name.Equals(name))
                        return v;
                }
            }
            throw new NoSuchVariableException("DSequence: getVariable()");
        }

        /// <summary> Checks for internal consistency.  For <code>DSequence</code>, verify that
        /// the variables have unique names.
        /// 
        /// </summary>
        /// <param name="all">for complex constructor types, this flag indicates whether to
        /// check the semantics of the member variables, too.
        /// </param>
        /// <throws>  BadSemanticsException if semantics are bad, explains why. </throws>
        /// <seealso cref="BaseType.CheckSemantics(bool)">
        /// </seealso>
        public override void CheckSemantics(bool all) {
            base.CheckSemantics(all);

            Utilities.UniqueNames(varTemplate, Name, TypeName);

            if (all) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e = varTemplate.GetEnumerator(); e.MoveNext();) {
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    BaseType bt = (BaseType) e.Current;
                    bt.CheckSemantics(true);
                }
            }
        }


        /// <summary> Write the variable's declaration in a C-style syntax. This
        /// function is used to create textual representation of the Data
        /// Descriptor Structure (DDS).  See <em>The OPeNDAP User Manual</em> for
        /// information about this structure.
        /// 
        /// </summary>
        /// <param name="os">        The <code>StreamWriter</code> on which to Print the
        /// declaration.
        /// </param>
        /// <param name="space">     Each line of the declaration will begin with the
        /// characters in this string.  Usually used for leading spaces.
        /// </param>
        /// <param name="Print_semi">a bool value indicating whether to Print a
        /// semicolon at the end of the declaration.
        /// </param>
        /// <param name="constrained"></param>
        /// <seealso cref="BaseType.PrintDeclaration(StreamWriter,string,bool)">
        /// </seealso>
        public override void PrintDeclaration(StreamWriter os, String space, bool print_semi, bool constrained) {
            // BEWARE! Since PrintDeclaration()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintDeclaration() in BaseType
            // lead to one signature, we must be careful to override that
            // SAME signature here. That way all calls to PrintDeclaration() for
            // this object lead to this implementation.

            //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
            os.WriteLine(space + TypeName + " {");
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = varTemplate.GetEnumerator(); e.MoveNext();) {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                BaseType bt = (BaseType) e.Current;
                //os.println("Printing declaration for \""+bt.getName()+"\"   constrained: "+constrained);
                bt.PrintDeclaration(os, space + "    ", true, constrained);
            }
            os.Write(space + "} " + Name);
            if (print_semi) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(";");
            }
        }

        /// <summary> Prints the value of the variable, with its declaration.  This
        /// function is primarily intended for debugging OPeNDAP applications and
        /// text-based clients such as geturl.
        /// 
        /// </summary>
        /// <param name="os">          the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="space">       this value is passed to the <code>PrintDeclaration</code> method,
        /// and controls the leading spaces of the output.
        /// </param>
        /// <param name="Print_decl_p">a bool value controlling whether the
        /// variable declaration is printed as well as the value.
        /// </param>
        /// <seealso cref="BaseType.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        public override void PrintValue(StreamWriter os, String space, bool print_decl_p) {
            if (print_decl_p) {
                PrintDeclaration(os, space, false);
                os.Write(" = ");
            }

            os.Write("{ ");
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e1 = allValues.GetEnumerator(); e1.MoveNext();) {
                // get next instance vector
                os.Write("{ ");
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                ArrayList v = (ArrayList) e1.Current;
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                for (IEnumerator e2 = v.GetEnumerator(); e2.MoveNext();) {
                    // get next instance variable
                    //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                    BaseType bt = (BaseType) e2.Current;
                    bt.PrintValue(os, "", false);
                    //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                    if (e2.MoveNext())
                        os.Write(", ");
                }
                os.Write(" }");
                //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
                if (e1.MoveNext())
                    os.Write(", ");
            }
            os.Write(" }");

            if (print_decl_p) {
                //UPGRADE_TODO: Method 'java.io.StreamWriter.println' was converted to 'System.IO.TextWriter.WriteLine' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioStreamWriterprintln_javalangString'"
                os.WriteLine(";");
            }
        }

        /// <summary> Reads data from a <code>DataInputStream</code>. This method is only used
        /// on the client side of the OPeNDAP client/server connection.
        /// 
        /// </summary>
        /// <param name="source">  a <code>DataInputStream</code> to Read from.
        /// </param>
        /// <param name="sv">      the <code>ServerVersion</code> returned by the server.
        /// </param>
        /// <param name="statusUI">the <code>StatusUI</code> object to use for GUI updates
        /// and user cancellation notification (may be null).
        /// </param>
        /// <throws>  EOFException      if EOF is found before the variable is completely </throws>
        /// <summary>                           deserialized.
        /// </summary>
        /// <throws>  IOException       thrown on any other InputStream exception. </throws>
        /// <throws>  DataReadException if an unexpected value was Read. </throws>
        /// <seealso cref="IClientIO.Deserialize">
        /// </seealso>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        //UPGRADE_NOTE: Synchronized keyword was removed from method 'Deserialize'. Lock expression was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1027'"
        public virtual void Deserialize(BinaryReader source, ServerVersion sv, IStatusUI statusUI) {
            lock (this) {
                // check for old servers
                if (sv.Major < 2 || (sv.Major == 2 && sv.Minor < 15)) {
                    oldDeserialize(source, sv, statusUI);
                }
                else {
                    // ************* Pulled out the getLevel() check in order to support the "new"
                    // and "improved" serialization of OPeNDAP sequences. 8/31/01 ndp
                    //            // top level of sequence handles start and end markers
                    //            if (getLevel() == 0) {
                    // loop until end of sequence
                    for (;;) {
                        sbyte marker = readMarker(source);

                        if (statusUI != null)
                            statusUI.IncrementByteCount(4);

                        if (marker == START_OF_INSTANCE)
                            deserializeSingle(source, sv, statusUI);
                        else if (marker == END_OF_SEQUENCE)
                            break;
                        else
                            throw new DataReadException("Sequence start marker not found");
                    }
                    // ************* Pulled out the getLevel() check in order to support the "new"
                    // and "improved" serialization of OPeNDAP sequences. 8/31/01 ndp
                    //            }
                    //	    else {
                    //                // lower levels only Deserialize a single instance at a time
                    //                deserializeSingle(source, sv, statusUI);
                    //            }
                }
            }
        }

        /// <summary> The old Deserialize protocol has a number of limitations stemming from
        /// its inability to tell when the sequence is Finished.  It's really only
        /// good for a Dataset containing a single sequence, or where the sequence is
        /// the last thing in the dataset.  To handle this, we just Read single
        /// instances until we get an IOException, then stop.
        /// 
        /// </summary>
        /// <param name="source">  a <code>DataInputStream</code> to Read from.
        /// </param>
        /// <param name="sv">      the <code>ServerVersion</code> returned by the server.
        /// </param>
        /// <param name="statusUI">the <code>StatusUI</code> object to use for GUI updates
        /// and user cancellation notification (may be null).
        /// </param>
        /// <throws>  IOException       thrown on any InputStream exception other than EOF </throws>
        /// <summary>                           (which is trapped here).
        /// </summary>
        /// <throws>  DataReadException if an unexpected value was Read. </throws>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        private void oldDeserialize(BinaryReader source, ServerVersion sv, IStatusUI statusUI) {
            try {
                for (;;) {
                    deserializeSingle(source, sv, statusUI);
                }
            }
            catch (EndOfStreamException ) {}
        }

        /// <summary> Deserialize a single row of the <code>DSequence</code>.
        /// 
        /// </summary>
        /// <param name="source">  a <code>DataInputStream</code> to Read from.
        /// </param>
        /// <param name="sv">      the <code>ServerVersion</code> returned by the server.
        /// </param>
        /// <param name="statusUI">the <code>StatusUI</code> object to use for GUI updates
        /// and user cancellation notification (may be null).
        /// </param>
        /// <throws>  EOFException      if EOF is found before the variable is completely </throws>
        /// <summary>                           deserialized.
        /// </summary>
        /// <throws>  IOException       thrown on any other InputStream exception. </throws>
        /// <throws>  DataReadException if an unexpected value was Read. </throws>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        private void deserializeSingle(BinaryReader source, ServerVersion sv, IStatusUI statusUI) {
            // create a new instance from the variable template Vector
            ArrayList newInstance = ArrayList.Synchronized(new ArrayList(10));
            for (int i = 0; i < varTemplate.Count; i++) {
                BaseType bt = (BaseType) varTemplate[i];
                newInstance.Add(bt.Clone());
            }
            // Deserialize the new instance
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            for (IEnumerator e = newInstance.GetEnumerator(); e.MoveNext();) {
                if (statusUI != null && statusUI.UserCancelled())
                    throw new DataReadException("User cancelled");
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                IClientIO bt = (IClientIO) e.Current;
                bt.Deserialize(source, sv, statusUI);
            }
            // add the new instance to the allValues vector
            allValues.Add(newInstance);
        }

        /// <summary> Reads a marker byte from the input stream.</summary>
        //UPGRADE_TODO: Class 'java.io.DataInputStream' was converted to 'System.IO.BinaryReader' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataInputStream'"
        private sbyte readMarker(BinaryReader source) {
            sbyte marker = (sbyte) source.ReadByte();
            // pad out to a multiple of four bytes
            sbyte unused;
            for (int i = 0; i < 3; i++)
                unused = (sbyte) source.ReadByte();

            return marker;
        }

        /// <summary> Writes a marker byte to the output stream.</summary>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        protected internal virtual void writeMarker(BinaryWriter sink, sbyte marker) {
            //for(int i=0; i<4; i++)
            sink.Write((byte) marker);
            sink.Write((byte) 0);
            sink.Write((byte) 0);
            sink.Write((byte) 0);
        }

        /// <summary> Writes data to a <code>DataOutputStream</code>. This method is used
        /// primarily by GUI clients which need to download OPeNDAP data, manipulate
        /// it, and then re-save it as a binary file.
        /// 
        /// </summary>
        /// <param name="sink">a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> </throws>
        /// <summary>                     exception.
        /// </summary>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public virtual void Externalize(BinaryWriter sink) {
            // loop until end of sequence
            for (int i = 0; i < allValues.Count; i++) {
                // ************* Pulled out the getLevel() check in order to support the "new"
                // and "improved" serialization of OPeNDAP sequences. 8/31/01 ndp
                //            if (getLevel() == 0)
                writeMarker(sink, START_OF_INSTANCE);

                ArrayList rowVec = (ArrayList) allValues[i];

                for (int j = 0; j < rowVec.Count; j++) {
                    IClientIO bt = (IClientIO) rowVec[j];
                    bt.Externalize(sink);
                }
            }
            // ************* Pulled out the getLevel() check in order to support the "new"
            // and "improved" serialization of OPeNDAP sequences. 8/31/01 ndp
            //        if (getLevel() == 0)
            writeMarker(sink, END_OF_SEQUENCE);
        }
    }
}